﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using LayeredArchitectureSample.Infrastructure;
using LayeredArchitectureSample.Infrastructure.Services;
using LayeredArchitectureSample.RandomDataProviders;
using LayeredArchitectureSample.ServiceContracts;

namespace LayeredArchitectureSample.ViewModel
{
    internal class RoutesViewModel : INotifyPropertyChanged
    {
        private readonly IServiceOperationInvoker<IRemoteRouteRepository> _remoteRepository;

        private readonly ObservableCollection<RouteViewModel> _routes;
        private RouteViewModel _currentlySelectedRoute;
        private bool _isSomethingSelected;
        private readonly string _somethingSelectedPropertyName;
        private readonly string _selectedRoutePropertyName;
        private readonly IRandomLocationProvider _randomLocationProvider;
        private readonly IExceptionAwareServiceCodeRunner _codeRunner;

        public RoutesViewModel(
            IEnumerable<RouteViewModel> routes,
            IServiceOperationInvoker<IRemoteRouteRepository> remoteRepository,
            IRandomLocationProvider randomLocationProvider,
            IExceptionAwareServiceCodeRunner codeRunner)
        {
            if (routes == null) throw new ArgumentNullException("routes");
            if (remoteRepository == null) throw new ArgumentNullException("remoteRepository");
            if (randomLocationProvider == null) throw new ArgumentNullException("randomLocationProvider");
            if (codeRunner == null) throw new ArgumentNullException("codeRunner");

            _remoteRepository = remoteRepository;
            _codeRunner = codeRunner;
            _randomLocationProvider = randomLocationProvider;

            _routes = new ObservableCollection<RouteViewModel>(routes);

            _somethingSelectedPropertyName = Reflection.GetPropertyName(() => this.IsSomethingSelected);
            _selectedRoutePropertyName = Reflection.GetPropertyName(() => this.CurrentlySelectedRoute);
        }

        public ObservableCollection<RouteViewModel> Routes
        {
            get { return _routes; }
        }

        public RouteViewModel CurrentlySelectedRoute
        {
            get { return _currentlySelectedRoute; }
            set
            {
                _currentlySelectedRoute = value;

                this.IsSomethingSelected = (_currentlySelectedRoute != null);
                EventRaiser.RaisePropertyChangedEvent(PropertyChanged, this, _selectedRoutePropertyName);
            }
        }

        public bool IsSomethingSelected
        {
            get {
                return _isSomethingSelected;
            }
            set {
                _isSomethingSelected = value;
                EventRaiser.RaisePropertyChangedEvent(PropertyChanged, this, _somethingSelectedPropertyName);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void RemoveSelectedRoute()
        {
            _codeRunner.RunCode(() =>
                                    {
                                        _remoteRepository.Invoke(x => x.RemoveRoute(CurrentlySelectedRoute.Id));

                                        _routes.Remove(CurrentlySelectedRoute);

                                        CurrentlySelectedRoute = null;
                                    });
        }

        public void AddNewRoute()
        {
            _codeRunner.RunCode(
                ()=>
                {
                    var randomLocations = _randomLocationProvider.GetRandomLocations(2);

                    var newRoute = _remoteRepository.Invoke(r => r.AddNewRoute(randomLocations));

                    _routes.Add(new RouteViewModel(newRoute.Waypoints.Select(wp=>new LocationViewModel(wp.Id, wp.Name)), newRoute.Id));
                });
        }
    }
}